<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>PF: Network Address Translation (NAT)</title>
<link rev="made" href="mailto:www@openbsd.org">
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta name="resource-type" content="document">
<meta name="description"   content="the OpenBSD FAQ page">
<meta name="keywords"      content="openbsd,faq,pf">
<meta name="distribution"  content="global">
</head>

<!--
Copyright (c) 2003, Nick Holland <nick@openbsd.org>
Copyright (c) 2003, 2004, Joel Knight <enabled@myrealbox.com>

Permission to use, copy, modify, and distribute this documentation for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.

THE DOCUMENTATION IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS DOCUMENTATION INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS DOCUMENTATION
-->

<body bgcolor="#ffffff" text="#000000">
<!-- Passes validator.w3.org, please keep it this way;
please, use a max of 72 chars per line -->

<a href="../../index.html">
<img alt="[OpenBSD]" height=30 width=141 src="../../images/smalltitle.gif" border="0">
</a>
<p>
[<a href="filter.html">Previous: Packet Filtering</a>]
[<a href="index.html">Contents</a>]
[<a href="rdr.html">Next: Traffic Redirection (Port Forwarding)</a>]

<p>
<h1><font color="#e00000">PF: Network Address Translation (NAT)</font></h1>

<hr>

<h3>Table of Contents</h3>
<ul>
<li><a href="#intro">Introduction</a>
<li><a href="#works">How NAT Works</a>
<li><a href="#filter">NAT and Packet Filtering</a>
<li><a href="#ipfwd">IP Forwarding</a>
<li><a href="#config">Configuring NAT</a>
<li><a href="#binat">Bidirectional Mapping (1:1 mapping)</a>
<li><a href="#except">Translation Rule Exceptions</a>
<li><a href="#status">Checking NAT Status</a>
</ul>

<hr>

<a name="intro"></a>
<h2>Introduction</h2>
Network Address Translation (NAT) is a way to map an entire network (or
networks) to a single IP address.  NAT is necessary when the number of
IP addresses assigned to you by your Internet Service Provider is less
than the total number of computers that you wish to provide Internet
access for. NAT is described in
<a href="http://www.geektools.com/rfc/rfc1631.txt">RFC 1631</a>,
"The IP Network Address Translator (NAT)."

<p>
NAT allows you to take advantage of the reserved address blocks
described in
<a href="http://www.geektools.com/rfc/rfc1918.txt">RFC 1918</a>,
"Address Allocation for Private Internets."
Typically, your internal network will be setup to use one or more of
these network blocks. They are:
<pre>
	10.0.0.0/8       (10.0.0.0 - 10.255.255.255)
	172.16.0.0/12    (172.16.0.0 - 172.31.255.255)
	192.168.0.0/16   (192.168.0.0 - 192.168.255.255)
</pre>

<p>
An OpenBSD system doing NAT will have at least two network adapters, one
to the Internet, the other to your internal network.  NAT will be
translating requests from the internal network so they appear to all be
coming from your OpenBSD NAT system.

<a name="works"></a>
<h2>How NAT Works</h2>
<p>
When a client on the internal network contacts a machine on the
Internet, it sends out IP packets destined for that machine. These
packets contain all the addressing information necessary to get them to
their destination. NAT is concerned with these pieces of information:
<ul>
<li>Source IP address (for example, 192.168.1.35)
<li>Source TCP or UDP port (for example, 2132)
</ul>

<p>
When the packets pass through the NAT gateway they will be modified so
that they appear to be coming from the NAT gateway itself. The NAT
gateway will record the changes it makes in its state table so that it
can a) reverse the changes on return packets and b) ensure that return
packets are passed through the firewall and are not blocked. For example,
the following changes might be made:
<ul>
<li>Source IP: replaced with the external address of the
gateway (for example, 24.5.0.5)
<li>Source port: replaced with a randomly chosen, unused port on the
gateway (for example, 53136)
</ul>

<p>
Neither the internal machine nor the Internet host is aware of these
translation steps. To the internal machine, the NAT system is simply an
Internet gateway. To the Internet host, the packets appear to come
directly from the NAT system; it is completely unaware that the
internal workstation even exists.

<p>
When the Internet host replies to the internal machine's packets, they
will be addressed to the NAT gateway's external IP (24.5.0.5) at the
translation port (53136). The NAT gateway will then search the state
table to determine if the reply packets match an already established
connection. A unique match will be found based on the IP/port
combination which tells PF the packets belong to a connection initiated
by the internal machine 192.168.1.35. PF will then make the opposite
changes it made to the outgoing packets and forward the reply packets on
to the internal machine.

<p>
Translation of ICMP packets happens in a similar fashion but without the
source port modification.

<a name="filter"></a>
<h2>NAT and Packet Filtering</h2>
<p>
<font color="#ff0000">NOTE:</font> Translated packets must still pass
through the filter engine and will be blocked or passed based on the
filter rules that have been defined. 
The <i>only</i> exception to this rule is when the <tt>pass</tt> keyword
is used within the <tt>nat</tt> rule.
This will cause the NATed packets to pass right through the filtering
engine.

<p>
Also be aware that since translation occurs <i>before</i> filtering, the
filter engine will see the <i>translated</i> packet with the translated
IP address and port as outlined in <a href="#works">How NAT Works</a>.

<!-- legacy anchor; can eventually be removed -->
<a name="enable"></a>
<a name="ipfwd"></a>
<h2>IP Forwarding</h2>
<p>
Since NAT is almost always used on routers and network gateways, it
will probably be necessary to enable IP forwarding so that packets can
travel between network interfaces on the OpenBSD machine.
IP forwarding is enabled using the 
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=sysctl&amp;sektion=3"
>sysctl(3)</a> mechanism:
<blockquote>
<tt>
# sysctl net.inet.ip.forwarding=1<br>
# sysctl net.inet6.ip6.forwarding=1 <i>(if using IPv6)</i>
</tt>
</blockquote>

<p>
To make this change permanent, the following lines should be added to
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=sysctl.conf&amp;sektion=5"
><tt>/etc/sysctl.conf</tt></a>:
<blockquote>
<tt>
net.inet.ip.forwarding=1<br>
net.inet6.ip6.forwarding=1
</tt>
</blockquote>

<p>
These lines are present but commented out (prefixed with a <tt>#</tt>)
in the default install. Remove the <tt>#</tt> and save the file. IP
forwarding will be enabled when the machine is rebooted.

<a name="config"></a>
<h2>Configuring NAT</h2>
The general format for NAT rules in <tt>pf.conf</tt> looks
something like this:
<blockquote>
<tt>
nat [pass] [log] on <i>interface</i> [<i>af</i>] from <i>src_addr</i> 
[port <i>src_port</i>] to \<br>
&nbsp;&nbsp;&nbsp;<i>dst_addr</i> [port <i>dst_port</i>] -&gt; 
<i>ext_addr</i> [<i>pool_type</i>] [static-port]
</tt>
</blockquote>

<dl>
<dt><tt>nat</tt>
<dd>The keyword that begins a NAT rule.

<dt><tt>pass</tt>
<dd>Causes translated packets to completely bypass the filter rules.

<dt><tt>log</tt>
<dd>Log matching packets via
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=pflogd&amp;sektion=8&amp;manpath=OpenBSD+4.3"
>pflogd(8)</a>.
Normally only the first packet that matches will be logged.
To log all matching packets, use <tt>log (all)</tt>.

<dt><tt><i>interface</i></tt>
<dd>The name or group of the network interface to translate packets on.

<dt><tt><i>af</i></tt>
<dd>The address family, either <tt>inet</tt> for IPv4 or <tt>inet6</tt>
for IPv6. PF is usually able to determine this parameter based on the
source/destination address(es).

<dt><tt><i>src_addr</i></tt>
<dd>The source (internal) address of packets that will be translated.
The source address can be specified as:
<ul>
<li>A single IPv4 or IPv6 address.
<li>A <a href="http://public.pacbell.net/dedicated/cidr.html">CIDR</a> 
network block.
<li>A fully qualified domain name that will be resolved via DNS when the
ruleset is loaded. All resulting IP addresses will be substituted into
the rule.
<li>The name or group of a network interface.
Any IP addresses assigned to the interface will be substituted into the
rule at load time.
<li>The name of a network interface followed by
<tt>/<i>netmask</i></tt> (e.g. <tt>/24</tt>). Each IP address on the
interface is combined with the netmask to form a CIDR network block
which is substituted into the rule.
<li>The name or group of a network interface followed by any one of these
modifiers: 
  <ul>
  <li><tt>:network</tt> - substitutes the CIDR network block (e.g.,
  192.168.0.0/24)
  <li><tt>:broadcast</tt> - substitutes the network broadcast address
  (e.g., 192.168.0.255)
  <li><tt>:peer</tt> - substitutes the peer's IP address on a
  point-to-point link
  </ul>
  <dl>
  <dd>In addition, the <tt>:0</tt> modifier can be appended to either an
  interface name/group or to any of the above modifiers to indicate that PF
  should not include aliased IP addresses in the substitution.
  These modifiers can also be used when the interface is contained in
  parentheses.
  Example: <tt>fxp0:network:0</tt>
  </dl>
<li>A <a href="tables.html">table</a>.
<li>Any of the above but negated using the <tt>!</tt> ("not") modifier.
<li>A set of addresses using a <a href="macros.html#lists">list</a>.
<li>The keyword <tt>any</tt> meaning all addresses
</ul>

<dt><tt><i>src_port</i></tt>
<dd>The source port in the Layer 4 packet header. Ports can be specified
as:
<ul>
<li>A number between 1 and 65535
<li>A valid service name from
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=services&amp;sektion=5"
><tt>/etc/services</tt></a>
<li>A set of ports using a <a href="macros.html#lists">list</a>
<li>A range:
	<ul>
	<li><tt>!=</tt> (not equal)
	<li><tt>&lt;</tt> (less than)
	<li><tt>&gt;</tt> (greater than)
	<li><tt>&lt;=</tt> (less than or equal)
	<li><tt>&gt;=</tt> (greater than or equal)
	<li><tt>&gt;&lt;</tt> (range)
	<li><tt>&lt;&gt;</tt> (inverse range)
	<dl>
	<dd>The last two are binary operators (they take two arguments) and
	do not include the arguments in the range.
	</dl>
	<li><tt>:</tt> (inclusive range)
	<dl>
	<dd>The inclusive range operator is also a binary operator and does
	include the arguments in the range.
	</dl>
	</ul>
</ul>
The <tt>port</tt> option is not usually used in <tt>nat</tt> rules
because the goal is usually to NAT all traffic regardless of the port(s)
being used.

<dt><tt><i>dst_addr</i></tt>
<dd>The destination address of packets to be translated. The destination
address is specified in the same way as the source address.

<dt><tt><i>dst_port</i></tt>
<dd>The destination port in the Layer 4 packet header. This port is
specified in the same way as the source port.

<dt><tt><i>ext_addr</i></tt>
<dd>The external (translation) address on the NAT gateway that packets
will be translated to. The external address can be specified as:
<ul>
<li>A single IPv4 or IPv6 address.
<li>A <a href="http://public.pacbell.net/dedicated/cidr.html">CIDR</a> 
network block.
<li>A fully qualified domain name that will be resolved via DNS when the
ruleset is loaded.
<li>The name of the external network interface. Any IP addresses assigned
to the interface will be substituted into the rule at load time.
<li>The name of the external network interface in parentheses 
<tt>( )</tt>. This tells PF to update the rule if the IP address(es) on
the named interface changes. This is highly useful when the external
interface gets its IP address via DHCP or dial-up as the ruleset
doesn't have to be reloaded each time the address changes.
<li>The name of a network interface followed by either one of these
modifiers: 
  <ul>
  <li><tt>:network</tt> - substitutes the CIDR network block (e.g.,
  192.168.0.0/24)
  <li><tt>:peer</tt> - substitutes the peer's IP address on a
  point-to-point link
  </ul>
  <dl>
  <dd>In addition, the <tt>:0</tt> modifier can be appended to either an
  interface name or to any of the above modifiers to indicate that PF
  should not include aliased IP addresses in the substitution.
  These modifiers can also be used when the interface is contained in
  parentheses.
  Example: <tt>fxp0:network:0</tt>
  </dl>
<li>A set of addresses using a <a href="macros.html#lists">list</a>.
</ul>

<dt><tt><i>pool_type</i></tt>
<dd>Specifies the type of <a href="pools.html">address pool</a> to use
for translation.

<dt><tt>static-port</tt>
<dd>Tells PF not to translate the source port in TCP and UDP packets.

</dl>

<p>
This would lead to a most basic form of this line similar to this:
<blockquote>
<tt>
nat on tl0 from 192.168.1.0/24 to any -&gt; 24.5.0.5
</tt>
</blockquote>

<p>
This rule says to perform NAT on the <tt>tl0</tt> interface for any
packets coming from 192.168.1.0/24 and to replace the source IP address
with 24.5.0.5.

<p>
While the above rule is correct, it is not recommended form.
Maintenance could be difficult as any change of the external or internal
network numbers would require the line be changed.  Compare instead with
this easier to maintain line (<tt>tl0</tt> is external, <tt>dc0</tt>
internal):
<blockquote>
<tt>
nat on tl0 from dc0:network to any -&gt; tl0
</tt>
</blockquote>

<p>
The advantage should be fairly clear: you can change the IP addresses of
either interface without changing this rule.

<p>
When specifying an interface name for the translation address as above,
the IP address is determined at pf.conf <i>load</i> time, not on the
fly.  If you are using DHCP to configure your external interface, this
can be a problem. If your assigned IP address changes, NAT will
continue translating outgoing packets using the old IP address. This
will cause outgoing connections to stop functioning. To get around this,
you can tell PF to automatically update the translation address by
putting parentheses around the interface name:
<blockquote>
<tt>
nat on tl0 from dc0:network to any -&gt; (tl0)
</tt>
</blockquote>

<p>
This method works for translation to both IPv4 and IPv6 addresses.

<a name="binat"></a>
<h2>Bidirectional Mapping (1:1 mapping)</h2>
A bidirectional mapping can be established by using the
<tt>binat</tt> rule. A <tt>binat</tt> rule establishes a one to one
mapping between an internal IP address and an external address. This can
be useful, for example, to provide a web server on the internal network
with its own external IP address. Connections from the Internet to the
external address will be translated to the internal address and
connections from the web server (such as DNS requests) will be
translated to the external address. TCP and UDP ports are never
modified with <tt>binat</tt> rules as they are with <tt>nat</tt>
rules.

<p>
Example:
<blockquote>
<tt>
web_serv_int = "192.168.1.100"<br>
web_serv_ext = "24.5.0.6"<br>
<br>
binat on tl0 from $web_serv_int to any -&gt; $web_serv_ext<br>
</tt>
</blockquote>

<a name="except"></a>
<h2>Translation Rule Exceptions</h2>
Exceptions can be made to translation rules by using the <tt>no</tt>
keyword. For example, if the NAT example above was modified to look
like this:
<blockquote>
<tt>
no nat on tl0 from 192.168.1.208 to any<br>
nat on tl0 from 192.168.1.0/24 to any -&gt; 24.2.74.79
</tt>
</blockquote>

<p>
Then the entire 192.168.1.0/24 network would have its packets
translated to the external address 24.2.74.79 except for 192.168.1.208.

<p>
Note that the first matching rule wins; if it's a <tt>no</tt> rule,
then the packet is not translated. The <tt>no</tt> keyword can also be
used with <tt>binat</tt> and <a href="rdr.html"><tt>rdr</tt></a> rules.

<a name="status"></a>
<h2>Checking NAT Status</h2>
To view the active NAT translations
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=pfctl&amp;sektion=8&amp;manpath=OpenBSD+4.3"
>pfctl(8)</a> is used with the <tt>-s state</tt> option. This option will list
all the current NAT sessions:

<pre>
   # pfctl -s state
   fxp0 TCP 192.168.1.35:2132 -&gt; 24.5.0.5:53136 -&gt; 65.42.33.245:22 TIME_WAIT:TIME_WAIT
   fxp0 UDP 192.168.1.35:2491 -&gt; 24.5.0.5:60527 -&gt; 24.2.68.33:53   MULTIPLE:SINGLE
</pre>

<p>
Explanations (first line only):

<dl>
<dt>fxp0
<dd>Indicates the interface that the state is bound to. The word
<tt>self</tt> will appear if the state is 
<a href="options.html#state-policy"><tt>floating</tt></a>.
</dl>

<dl>
<dt>TCP
<dd>The protocol being used by the connection.
</dl>

<dl>
<dt>192.168.1.35:2132
<dd>The IP address (192.168.1.35) of the machine on the internal
network. The source port (2132) is shown after the address. This is also
the address that is replaced in the IP header.
</dl>

<dl>
<dt>24.5.0.5:53136
<dd>The IP address (24.5.0.5) and port (53136) on the gateway that
packets are being translated to.
</dl>

<dl>
<dt>65.42.33.245:22
<dd>The IP address (65.42.33.245) and the port (22) that the internal
machine is connecting to.
</dl>

<dl>

<dt>TIME_WAIT:TIME_WAIT
<dd>This indicates what state PF believes the TCP connection to be in.
</dl>

<p>
[<a href="filter.html">Previous: Packet Filtering</a>]
[<a href="index.html">Contents</a>]
[<a href="rdr.html">Next: Traffic Redirection (Port Forwarding)</a>]

<p>
<hr>
<a href="index.html"><img height="24" width="24" src="../../images/back.gif" border="0" alt="[back]"></a> 
<a href="mailto:www@openbsd.org">www@openbsd.org</a>
<br>
<small>$OpenBSD: nat.html,v 1.28 2008/07/27 17:13:47 nick Exp $</small>

</body>
</html> 
